package whisper.service.auth.shiro.filter;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
import whisper.common.exception.authorization.AuthenticationException;
import whisper.common.support.jwt.JWTConstant;
import whisper.common.support.response.WebResponseCode;
import whisper.service.auth.shiro.token.JWTToken;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * JWT token 过滤
 *
 *  调用过程  isAccessAllowed -> isLoginAttempt -> executeLogin -> realm -> doGetAuthenticationInfo -> doGetAuthorizationInfo
 *
 * Created by JT on 2018/5/29
 */
public class JWTFilter extends BasicHttpAuthenticationFilter {

    /**
     * 判断用户是否想要登录
     *
     * 检测 header 和 parameters 里面是否包含 JWT 令牌的KEY
     * @param request
     * @param response
     * @return
     */
    @Override
    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
        String token = ((HttpServletRequest)request).getHeader(JWTConstant.JWT_TOKEN_FLAG);
        token = StringUtils.isBlank(token) ? request.getParameter(JWTConstant.JWT_TOKEN_FLAG) : null;
        return StringUtils.isNotBlank(token);
    }

    /**
     * 登入
     * @param request
     * @param response
     * @param mappedValue
     * @return
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if (!isLoginAttempt(request, response))
            throw new AuthenticationException(WebResponseCode.CODE_ERROR,  WebResponseCode.MESSAGE_ERROR_TOKEN);
        try {
            boolean isLogin = this.executeLogin(request, response);
            if (!isLogin)
                throw new AuthenticationException(WebResponseCode.CODE_ERROR,  WebResponseCode.MESSAGE_ERROR_TOKEN);
        } catch (Exception e) {
            throw new AuthenticationException(WebResponseCode.CODE_ERROR,  WebResponseCode.MESSAGE_ERROR_TOKEN);
        }
        return true;
    }

    /**
     * 执行登入
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response){
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String token = httpServletRequest.getHeader(JWTConstant.JWT_TOKEN_FLAG);
        if (StringUtils.isBlank(token))
            token = httpServletRequest.getParameter(JWTConstant.JWT_TOKEN_FLAG);
        this.getSubject(request, response).login(new JWTToken(token));
        return true;
    }

    /**
     * 跨域
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
        // 跨域时会首先发送一个option请求，这里我们给option请求直接返回正常状态
        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            return false;
        }
        return super.preHandle(request, response);
    }
}
